// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml;

namespace BlueOnionSoftware.Bloget
{
    internal class RpcView : View
    {
        internal RpcView(Bloget blogetArg)
            : base(blogetArg)
        {
        }

        protected override string RootClassId()
        {
            return null;
        }

        protected override void ShowView()
        {
            if (Bloget.Page.Request.RequestType == "POST")
            {
                XmlRpcCall();
            }

            else
            {
                RealSimpleDiscovery();
            }

            Bloget.Page.Response.End();
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void XmlRpcCall()
        {
            XmlRpcMethodResponse methodResponse;
            var methodCallName = string.Empty;

            try
            {
                var methodCall = GetRpcRequest();
                methodCallName = methodCall.Name;
                Log.RpcRequest(Bloget, methodCallName);

                switch (methodCall.Name)
                {
                    case PingBackServer.MethodPing:
                        methodResponse = PingBackServer.Ping(methodCall, Bloget);
                        break;

                    case MetaWebLog.MethodNewPost:
                    case MetaWebLog.MethodEditPost:
                        methodResponse = MetaWebLog.Post(methodCall, Bloget);
                        break;

                    case MetaWebLog.MethodGetPost:
                        methodResponse = MetaWebLog.GetPost(methodCall, Bloget);
                        break;

                    case MetaWebLog.MethodGetCategories:
                        methodResponse = MetaWebLog.GetCategories(methodCall, Bloget);
                        break;

                    case MetaWebLog.MethodGetRecentPosts:
                        methodResponse = MetaWebLog.GetRecentPosts(methodCall, Bloget);
                        break;

                    case MetaWebLog.MethodNewMediaObject:
                        methodResponse = MetaWebLog.NewMediaObject(methodCall, Bloget);
                        break;

                    case Blogger.MethodDeletePost:
                        methodResponse = Blogger.DeletePost(methodCall, Bloget);
                        break;

                    case Blogger.MethodGetUsersBlogs:
                        methodResponse = Blogger.GetUsersBlogs(methodCall, Bloget);
                        break;

                    case Blogger.MethodGetUserInfo:
                        methodResponse = Blogger.GetUserInfo(methodCall, Bloget);
                        break;

                    default:
                        methodResponse = new XmlRpcMethodResponse {FaultString = "Unrecognized Rpc request (" + methodCallName + ")"};
                        break;
                }
            }

            catch (Exception ex)
            {
                methodResponse = new XmlRpcMethodResponse {FaultString = ex.Message};
                Log.Exception(Bloget, "BlogetRpc.CreateControls", ex);
            }

            if (string.IsNullOrEmpty(methodResponse.FaultString))
            {
                Log.RpcRequestAccepted(Bloget, methodCallName);
            }

            else
            {
                Log.RpcRequestRejected(Bloget, methodCallName, methodResponse.FaultString);
            }

            try
            {
                using (var writer = XmlRpc.CreateXmlWriter(Bloget.Page))
                {
                    methodResponse.Serialize(writer);
                }
            }

            catch (Exception ex)
            {
                Log.Exception(Bloget, "BlogetRpc.CreateControls (Serialize)", ex);
            }
        }

        private XmlRpcMethodCall GetRpcRequest()
        {
            var xmlSettings = new XmlReaderSettings
            {
                IgnoreComments = true,
                IgnoreProcessingInstructions = true,
                IgnoreWhitespace = true
            };

            string rpcRequest;

            using (var streamReader = new StreamReader(Bloget.Page.Request.InputStream))
            {
                rpcRequest = streamReader.ReadToEnd();
            }

            try
            {
                using (var stringReader = new StringReader(rpcRequest))
                {
                    using (var reader = XmlReader.Create(stringReader, xmlSettings))
                    {
                        return XmlRpc.ReadMethod(reader);
                    }
                }
            }

            catch (Exception)
            {
                Log.RpcRequest(Bloget, "Exception in GetRpcRequest rethrown, original request:" + rpcRequest);
                throw;
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void RealSimpleDiscovery()
        {
            try
            {
                using (var writer = XmlRpc.CreateXmlWriter(Bloget.Page))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("rsd", "http://archipelago.phrasewise.com/rsd");
                    writer.WriteAttributeString("version", "1.0");
                    writer.WriteStartElement("service");
                    writer.WriteElementString("engineName", "Bloget");
                    writer.WriteElementString("engineLink", "http://blueonionsoftware.com/Bloget.aspx");
                    writer.WriteElementString("homePageLink", "http://blueonionsoftware.com/");
                    writer.WriteStartElement("apis");
                    writer.WriteStartElement("api");
                    writer.WriteAttributeString("name", "MetaWeblog");
                    writer.WriteAttributeString("preferred", "true");
                    writer.WriteAttributeString("apiLink", Bloget.Page.Request.Url.ToString());
                    writer.WriteAttributeString("blogID", "1");
                    writer.WriteEndDocument();
                    writer.Flush();
                }
            }

            catch (Exception ex)
            {
                Log.Exception(Bloget, "BlogetRpc.RealSimpleDiscovery", ex);
            }
        }
    }
}